home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 6 / QRZ Ham Radio Callsign Database - Volume 6.iso / mac / files / amiga / csrc720j.lzh / timezone.c < prev    next >
C/C++ Source or Header  |  1993-04-21  |  7KB  |  230 lines

  1. /* timezone.c
  2. */
  3. #include <time.h>
  4.  
  5. /* Day number of first Sunday in April and last Sunday in October */
  6. int dst_start,dst_end;
  7.  
  8.  
  9. int daylight = 0;       /* non-zero if local timezone uses DST */
  10.  
  11. /* Cumulative days per month. Used to figure out first or last Sunday
  12.    in a month. For the first Sunday in a month start with the cumulative
  13.    number of days in the previous month. For the last Sunday in a month
  14.    use the cumulative days for that month minus 7.
  15.    The time routine uses Jan 1st as day zero.
  16. */
  17. int dpm[12] = {31,59,90,120,151,181,212,243,273,304,334,365};
  18.  
  19. /* Find a timezone string. If s is a non-null string, use it.
  20.    Otherwise check for the environment variable TZ_CHU in the system
  21.    or Manx.
  22.    If there's nothing valid, return -900 which is an impossible number
  23.    of minutes for the correction to UTC.
  24. */
  25. gettz(s)
  26. char *s;
  27. {
  28.    register char *p;
  29.    extern int zone();
  30.    char zonestr[10];
  31.    zonestr[0] = 0;
  32.    if(s && *s) {
  33.       strcpy(zonestr,s);
  34.    }
  35.    else {
  36.       /* Get the local time zone */
  37.       p = getenv("TZ_CHU");
  38.       if(p)strcpy(zonestr,p);
  39.       else {
  40.          /* If system one isn't there, try the MANX one */
  41.          p = getenv("MANX/TZ_CHU");
  42.          if(p)strcpy(zonestr,p);
  43.       }
  44.    }
  45.    if(zonestr[0] == 0) {
  46.       printf("ERROR: Timezone is not set in default file nor in TZ_CHU\n");
  47.       return(-900);  /* -900 is an impossible number of minutes which is
  48.                         tested for later in the program
  49.                      */
  50.    }
  51.    else {
  52.       return(zone(&zonestr[0]));
  53.    }
  54. }
  55.  
  56. /* Get timezone in number of minutes east(-ve) or west(+ve) of Greenwich.
  57.    Return number of minutes represented by the string in *s.
  58.    Set the daylight flag if the string ends with a valid DST indicator.
  59. */
  60. zone(s)
  61. char *s;
  62. {
  63.    register char *p,sign;
  64.    register long adj;
  65.  
  66.    p = s;
  67.    while((*p == ' ') || (*p == '\t'))p++;
  68.    sign = 1;
  69.    if(*p == '-') {
  70.       p++;
  71.       sign = -1;
  72.    }
  73.    adj = atoi(p)*60;
  74.    while(isdigit(*p))p++;
  75.    if(*p == ':') {
  76.       p++;
  77.       adj += atoi(p);
  78.       while(isdigit(*p))p++;
  79.    }
  80.    switch(*p) {
  81.    case 'd':   /* North America - begin April to end October  */
  82.    case 'D':
  83.    case 'u':   /* U.K.          - end March to end October    */
  84.    case 'U':
  85.    case 'e':   /* Europe + CIS  - end March to end September  */
  86.    case 'E':
  87.    case 'c':   /* China         - Apr 12 to Sept 12           */
  88.    case 'C':
  89.       daylight = *p;
  90.    }
  91.    /* The adjustment cannot exceed 12 hours */
  92.    if(adj > 720) {
  93.       printf("ERROR: timezone correction is too large\n");
  94.       daylight = 0;
  95.       return(-900);
  96.    }
  97.    return(adj*sign);
  98. }
  99.  
  100. /*
  101.    If daylight savings not used, or not currently in effect then just
  102.    return the local standard time adjustment. Otherwise correct the
  103.    standard time adjustment for daylight savings time.
  104.    Need local day of the year (1-366), local hour (0-23)
  105.    and standard timezone adjustment in minutes.
  106. */
  107. dst(adjust)
  108. int adjust;
  109. {
  110.    /* adjust is the local standard time in minutes east(-ve) or west(+ve)
  111.       of Greenwich. This routine checks to see if daylight savings time
  112.       is required and, if so and daylight savings is in effect, the local
  113.       standard time is adjusted accordingly
  114.    */
  115.    short day,hour;
  116.    time_t ltime;
  117.    register struct tm *tp;
  118.    int dstflag;
  119.  
  120.    if(!daylight)return(adjust);
  121.  
  122.    dstflag = 0;
  123.    time(<ime);
  124.    tp = localtime(<ime);
  125.    day = tp->tm_yday + 1;
  126.    hour = tp->tm_hour;
  127.  
  128.    /* Northern Hemisphere */
  129.    if((daylight >= 'a') && (daylight <= 'z')) {
  130.       if((day < dst_start) || (day > dst_end))return(adjust);
  131.  
  132.       /* Now: if DST is in effect, determine if it should be applied */
  133.       if((day > dst_start) && (day < dst_end))dstflag++;
  134.       else if((day == dst_end) && (hour < 2))dstflag++;
  135.       else if((day == dst_start) && (hour >= 2))dstflag++;
  136.       if(dstflag) {
  137.          adjust -= 60;
  138.       }
  139.    }
  140.    else {
  141.    /* Southern Hemisphere */
  142.       if((day > dst_start) && (day < dst_end))return(adjust);
  143.  
  144.       /* Now: if DST is in effect, determine if it should be applied */
  145.       if((day < dst_start) || (day > dst_end))dstflag++;
  146.       else if((day == dst_end) && (hour < 2))dstflag++;
  147.       else if((day == dst_start) && (hour >= 2))dstflag++;
  148.       if(dstflag) {
  149.          adjust -= 60;
  150.       }
  151.    }
  152.    return(adjust);
  153. }
  154.  
  155. /*
  156.    The definition of DST in North America is the first Sunday in April
  157.    to the last Sunday in October.
  158.    For the U.K. it is last Sunday in March to last Sunday in October.
  159.    For Europe and the CIS, it is the last Sunday in March to last Sunday
  160.    in September.
  161.    China uses April 12th to Sept 12th.
  162.    Australia and New Zealand probably use last Sunday in October to last
  163.    Sunday in March, but will have to check this out.
  164.  
  165.    Compute the first Sunday in April and last Sunday in October for the
  166.    DST  adjustment. Don't bother if daylight flag is not set.
  167.    This routine must be called once before dst() is used and in the
  168.    unlikely event that your computer never crashes, it must be called
  169.    once per year after that.
  170.    last_dstyear saves the last year that dstdates was called so you can
  171.    add some code to check that the year hasn't changed
  172. */
  173. int last_dstyear;
  174. dstdates()
  175. {
  176.    short days;
  177.    time_t ltime;
  178.    register struct tm *tp;
  179.    short find_sunday;
  180.  
  181.    find_sunday = 1;
  182.    if(!daylight)return;
  183.  
  184.    time(<ime);
  185.    tp = localtime(<ime);
  186.    last_dstyear = tp->tm_year;
  187.    switch(toupper(daylight)) {
  188.    case 'D':
  189.       dst_start = dpm[3];      /* first Sunday in April  */
  190.       dst_end =   dpm[10]-7;   /* last Sunday in October */
  191.       break;
  192.    case 'U':
  193.       dst_start = dpm[3] - 7;  /* end of March */
  194.       dst_end   = dpm[10] - 7; /* end of Oct  */
  195.       break;
  196.    case 'E':
  197.       dst_start = dpm[3] - 7;  /* End of march */
  198.       dst_end   = dpm[9] - 7;  /* End of Sept */
  199.       break;
  200.    case 'C':
  201.       dst_start = dpm[3]+11;    /* Apr 12 */
  202.       dst_end   = dpm[9]+11;    /* Sep 12 */
  203.       find_sunday = 0;        /* Don't look for Sunday */
  204.       break;
  205.    }
  206.    /* Check for leap year */
  207.    /* Technically, this calculation is incorrect. It does not check for
  208.       years ending in 00 which are not leap years. But the year 2000
  209.       IS a leap year, so the error won't hit until the year 2100 and
  210.       I won't be around to collect bug reports.
  211.    */
  212.    if((tp->tm_year%4) == 0){
  213.       dst_start += 1;
  214.       dst_end += 1;
  215.    }
  216.    if(find_sunday) {
  217.       days = (dst_start + tp->tm_wday)%7;
  218.       if(days)dst_start += 7 - days;
  219.  
  220.       days = (dst_end + tp->tm_wday)%7;
  221.       if(days)dst_end += 7 - days;
  222.    }
  223.  
  224. /* Adjust the days so that Jan 1st is day #1 instead of the zero returned
  225.    by the localtime() routine
  226. */
  227.    dst_start++;
  228.    dst_end++;
  229. }
  230.